// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)

#include "netlib/base/time_stamp.h"

#include <sys/time.h>

#include <cstdio>

#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif

#include <cinttypes>

using namespace netlib;

static_assert(sizeof(Timestamp) == sizeof(int64_t), "Timestamp should be same size as int64_t");

std::string Timestamp::ToString() const {
	char buf[32] = {0};
	int64_t seconds = micro_seconds_since_epoch_ / kMicroSecondsPerSecond;
	int64_t microseconds = micro_seconds_since_epoch_ % kMicroSecondsPerSecond;
	snprintf(buf, sizeof(buf), "%" PRId64 ".%06" PRId64 "", seconds, microseconds);
	return buf;
}

std::string Timestamp::ToFormattedString(bool showMicroseconds) const {
	char buf[64] = {0};
	auto seconds = static_cast<time_t>(micro_seconds_since_epoch_ / kMicroSecondsPerSecond);
	struct tm tm_time;
	localtime_r(&seconds, &tm_time);

	if (showMicroseconds) {
		int microseconds = static_cast<int>(micro_seconds_since_epoch_ % kMicroSecondsPerSecond);
		snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d", tm_time.tm_year + 1900,
		         tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_hour, tm_time.tm_min,
		         tm_time.tm_sec, microseconds);
	} else {
		snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d", tm_time.tm_year + 1900,
		         tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_hour, tm_time.tm_min,
		         tm_time.tm_sec);
	}
	return buf;
}

Timestamp Timestamp::Now() {
	struct timeval tv;
	gettimeofday(&tv, nullptr);
	int64_t seconds = tv.tv_sec;
	return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);
}
